package mathy.c;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import mathy.wili.c.Log9;
/**
 *   Lighter than C2.java. independent of other jar!
 */
@SuppressWarnings("all")
public class Ca {
	public static enum StaticStatus {//c.Ca$StaticStatus
		eq, gosuPatch
	}
	public static StaticStatus staticStat;

	public static final Boolean FALSE = Boolean.FALSE, TRUE = Boolean.TRUE;
	public static void pause() {
	}

	public static <K> Set<K> setOf(K... params) {
		HashSet<K> set = new HashSet<K>(params.length + 5);
		for (Object param : params) {
			set.add((K) param);
		}
		return set;
	}

	public static String repeat(String s, int times) {
		StringBuilder sb = new StringBuilder(s.length() * times);
		for (int i = 0; i < times; i++) {
			sb.append(s);
		}
		return sb.toString();
	}

	public static Object[] castObjToArray(Object obj) {
		if (obj instanceof Object[]) {
			return (Object[]) obj;
		}
		if (obj.getClass().isArray()) {
			int len = Array.getLength(obj);
			Object[] ret = new Object[len];
			for (int k = 0; k < ret.length; k++) {
				ret[k] = Array.get(obj, k);
			}
			return ret;
		} else {
			return new Object[] { obj };
		}
	}

	public static void asert(boolean is, Object... msgs) {
		if (!is) {
			throw new RuntimeException(concatStrs("", msgs));
		}
	}

	public static String concatStrs(String deli, Object... oo) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < oo.length; i++) {
			if (i > 0)
				sb.append(deli);
			sb.append(oo[i]);
		}
		return sb.toString();
	}

	public static String strOfEnum(Enumeration en, String deli) {
		StringBuilder sb = new StringBuilder();
		boolean first = true;
		while (en.hasMoreElements()) {
			if (first) {
				first = false;
			} else {
				sb.append(deli);
			}
			sb.append(en.nextElement());
		}
		return sb.toString();
	}
	final static String NL = "\n";

	public static String NULL = "null";
	//
	private static String lineStrOfLines(Object s0) {
		if (s0 == null)
			return "null";
		return s0.toString().replaceAll("\n", "/n").replaceAll("\\s+", " ");
	}

	private static TreeMap treeMapOf(Map map) {
		if (Boolean.FALSE) {
			// may has ClassCastException: java.lang.Integer cannot be cast to
			// java.lang.String
			TreeMap map2 = new TreeMap(map);
			return map2;
		} else {
			TreeMap map2 = new TreeMap(map);
			for (Object k : map.keySet()) {
				map2.put(k + "", map.get(k));
			}
			return map2;
		}
	}

	/**
	 * @param map
	 * @param curDepth 当前深度。深度依次是1,2,...maxDepth.
	 * @param maxDepth
	 * @param dent     e.g. "\n " 表示每item换行且缩进一个字符。
	 * @param skipSet
	 * @return
	 */
	static String strOfMap(Map map, int curDepth, int maxDepth, String dent, Set skipSet, Set toStringSet) {
		if (map == null)
			return "null";
		if (map.size() == 0)
			return "{}";
		Map treeMap = map;// treeMapOf(map);
		if (curDepth > maxDepth)
			return map == null ? "" : map.toString().replaceAll("\n", "/n");
		if (skipSet.contains(map)) {
			return "ref..";
		}
		skipSet.add(map);
		StringBuilder sb = new StringBuilder(map.size() * 10);
		sb.append(dent);
		sb.append('{');
		String dent2 = dent == null ? null : dent + DENT_INC;
		boolean first = true;
		for (Object key : treeMap.keySet()) {// 按自然序输出各成员,每成员站一行.。
			if ("_CLIENT_LOCALE_".equals(key))
				continue;
			if ("locale".equals(key)) {
				continue;
			}
			Object value = treeMap.get(key);
			if (skipNullValue && value == null) {
				continue;
			}
			String s0;
			if (first) {
				first = false;
			} else {
				sb.append(",");
			}
			sb.append(dent2 == null ? "" : dent2);
			sb.append(lineStrOfLines(key));// replace "\n" to "/n"
			sb.append(":");
			if (value instanceof String) {
				sb.append(lineStrOfLines(value));
			} else {
				StringBuilder sb2 = new StringBuilder(10);
				if (curDepth >= maxDepth) {
					sb.append(lineStrOfLines(sb2.toString()));
				} else {
					sb.append(sb2.toString());
				}
			}
		}
		sb.append(dent);
		sb.append('}');
		return sb.toString();
	}
	static Class[] clsArr = { String.class, byte.class, Byte.class, char.class, Character.class, short.class,
			Short.class, int.class, Integer.class, long.class, Long.class, double.class, Double.class, boolean.class,
			Boolean.class };

	static Set<Class<?>> clsSet = new HashSet(Arrays.asList(clsArr));
	public static boolean isPrimitiveWS(Class cls) {
		if (cls.isPrimitive())
			return true;
		return clsSet.contains(cls);
	}
	static final String DENT_INC = "  ";

	static final boolean skipNullValue = true;
	public static Map<String, Field> mapOfFields(Field[] ff) {
		Map<String, Field> map = new TreeMap<String, Field>();// ordered is good
																// on some
																// situation.
		for (int i = 0; i < ff.length; i++) {
			map.put(ff[i].getName(), ff[i]);
		}
		return map;
	}

	public static Object valueOfField(Field fd, Object obj, Object defaultValue) {
		try {
			fd.setAccessible(true);
			return fd.get(obj);
		} catch (Exception e) {
			e.printStackTrace();
			return defaultValue;
		}
	}

	/**
	 * check if every elements in array a and b are equals. <br>
	 * e.g, new Object{1,2} is equals to new int[]{1,2}
	 */
	private static <T> boolean isEqualsArray(T arr1, T arr2) {// good.
		Class<?> ca = arr1.getClass(), cb = arr2.getClass();
		if (ca.isArray() != cb.isArray())
			return false;
		int len = Array.getLength(arr1);
		int len2 = Array.getLength(arr2);
		if (len != len2)
			return false;
		for (int i = 0; i < len; i++) {
			Object ai = Array.get(arr1, i);
			Object bi = Array.get(arr2, i);
			if (!isEquals(ai, bi, false)) {
				return false;
			}
		}
		return true;
	}

	/** align left if $align<0, align right if $align>0, else align center. */
	public static String align(Object obj, int width, int align) {
		/*
		 * may be it's result in CMD not as you've expected, because: 1.the width of a
		 * string in CMD is relevant to it's FONT. 2.width of chines char is nearly 1.9
		 * times of english char.
		 */
		String s0 = obj == null ? null : "" + obj;
		if (s0 == null)
			return NULL + Ca.repeat(" ", width - NULL.length());
		s0 = s0.trim();
		if (s0.length() >= width)
			return s0;
		int len = s0.getBytes().length;
		if (align < 0) {
			return width > len ? s0 + Ca.repeat(" ", width - len) : s0;
		} else if (align > 0) {
			return width > len ? Ca.repeat(" ", width - len) + s0 : s0;
		} else {
			int gap = (width - len) >> 1;
			String space = Ca.repeat(" ", gap);
			if ((width - len) % 2 == 0) {
				return space + s0 + space;
			} else {
				return space + s0 + space + ' ';
			}
		}
	}

	@SuppressWarnings("rawtypes")
	public static boolean isBlank(Object obj, boolean ignoresBlankContent) {
		if (obj == null)
			return true;
		if (obj instanceof String)
			return ((String) obj).trim().length() == 0;
		if (obj instanceof Map) {
			if (((Map) obj).isEmpty())
				return true;
			if (!ignoresBlankContent)
				return false;
			for (Object value : ((Map) obj).values()) {
				if (!isBlank(value, ignoresBlankContent)) {
					return false;
				}
			}
			return true;
		}
		if (obj instanceof Collection) {
			if (((Collection) obj).isEmpty())
				return true;
			if (!ignoresBlankContent)
				return false;
			Iterator it = ((Collection) obj).iterator();
			while (it.hasNext()) {
				if (!isBlank(it.next(), ignoresBlankContent))
					return false;
			}
			return true;
		}
		if (obj.getClass().isArray()) {
			int len = Array.getLength(obj);
			if (len == 0)
				return true;
			if (!ignoresBlankContent)
				return false;
			for (int i = 0; i < len; i++) {
				if (!isBlank(Array.get(obj, i), ignoresBlankContent)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * test if every element of a and b has equal value. <br>
	 */
	static boolean isEquals(Object aObj, Object bObj, boolean skipBlankValue) {
		if (aObj == bObj)
			return true;
		if (aObj == null) {
			if (skipBlankValue) {
				return isBlank(bObj, skipBlankValue);
			}
			return false;
		} else if (bObj == null) {
			if (skipBlankValue) {
				return isBlank(aObj, skipBlankValue);
			}
			return false;
		} else if (aObj.equals(bObj)) {
			return true;
		} else if (isBlank(aObj, skipBlankValue) && isBlank(bObj, skipBlankValue)) {
			return true;
		} else if (aObj instanceof Number && bObj instanceof Number) {
			return ((Number) aObj).doubleValue() == ((Number) bObj).doubleValue();
		}
		Class<?> clsA = aObj.getClass(), clsB = bObj.getClass();
		if (!clsA.equals(clsB))
			return false;
		// -----------------------------Number
		if (aObj instanceof Number) {
			Number aa = (Number) aObj, bb = (Number) bObj;
			if (aa.doubleValue() == bb.doubleValue())
				return true;
			return false;
		}
		// -----------------------------isArray
		if (clsA.isArray()) {
			if (isEqualsArray(aObj, bObj))
				return true;
			return false;
		}
		// -----------------------------List
		if (aObj instanceof List) {
			List la = (List) aObj;
			List lb = (List) bObj;
			if (la.size() != lb.size())
				return false;
			for (int i = 0; i < la.size(); i++) {
				if (!isEquals(la.get(i), lb.get(i), skipBlankValue))
					return false;
			}
			return true;
		}
		// -----------------------------Set
		if (aObj instanceof Set && bObj instanceof Set) {
			Set set1 = (Set) aObj;
			Set set2 = (Set) bObj;
			if (set1.size() != set2.size())
				return false;
			for (Object e : set1) {
				if (!set2.contains(e))
					return false;
			}
			return true;
		}
		// -----------------------------Map
		if (aObj instanceof Map && bObj instanceof Map) {
			Map m1 = (Map) aObj;
			Map m2 = (Map) bObj;
			if (m1.size() != m2.size())// C2.printObj(m1);
				return false;
			for (Object k1 : m1.keySet()) {
				Object v2 = m2.get(k1);
				if (k1.equals("screens"))
					Ca.pause();
				if (!isEquals(m1.get(k1), v2, skipBlankValue)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	public static <T> String concatList(Collection<T> list, String deli) {
		StringBuilder sb = new StringBuilder(list.size() * 4);
		int ind = -1;
		for (T ele : list) {
			if (++ind > 0 && !deli.isEmpty())
				sb.append(deli);
			String st = ele == null ? null : ele.toString();
			sb.append(st);
		}
		return sb.toString();
	}

	public static String concat(String deli, String... msgs) {
		return concat(deli, (Object[]) msgs);
	}

	public static String concat(String deli, Object... msgs) {
		if (msgs.length == 1) {
			return msgs[0] == null ? (String) msgs[0] : msgs[0].toString();
		} else {
			return concatList(Arrays.asList(msgs), deli);
		}
	}

	public static void asert(boolean is, Object msg) {
		if (!is) {
			throw new RuntimeException(msg.toString());
		}
		Ca.pause();
	}
	public static class MiscException extends RuntimeException {
		public final String kind;
		public MiscException(String key, Throwable msg) {
			super(msg);
			this.kind = key;
		}

		public MiscException(String key, String msg) {
			super(msg);
			this.kind = key;
		}
	}
	public static RuntimeException newMiscException(String kind, Object msg) {
		if (msg instanceof Throwable)
			return new MiscException(kind, (Throwable) msg);
		return new MiscException(kind, msg.toString());
	}

	public static RuntimeException newRuntimeException(Object msg) {
		if (msg instanceof Throwable)
			return new RuntimeException((Throwable) msg);
		return new RuntimeException(msg.toString());
	}

	public static void exit(Object msg) {
		if (msg instanceof Exception) {
			((Exception) msg).printStackTrace();
		} else {
			new Exception(msg.toString()).printStackTrace();
		}
		System.exit(0);
	}

	public static void log2(int opt, org.apache.log4j.Logger log, Object... msgs) {
		if ("".isEmpty() || opt < 0)
			return;
		debug00(opt, log, msgs);
	}

	/**
	 * D:/bearJ/autoeq2/log/eq1.log
	 */
	private static void debug00(int opt, org.apache.log4j.Logger log, Object... msgs) {
		if (++inc == 13)
			Ca.pause();
		if (opt < 0)
			return;
		String msg = strOfObjs(msgs);
		log.debug("\n" + inc + "," + msg);
	}

	/**
	 * 	根据需要可以缩进或紧凑显示。
	 */
	public static void strOfObj(Object value, List<String> toList) {
		if (Boolean.FALSE) {
			Arrays.deepToString(null);//这个不行...
		}
	}
	public static int LogN = 78;
	public static String strOfObjs(Object... objs) {
		if (objs.length == 0)
			return "";
		if (objs.length == 1)
			return String.valueOf(objs[0]);
		if (objs.length == 2)
			return String.valueOf(objs[0]) + String.valueOf(objs[1]);
		int size = 0;
		for (int i = 0; i < objs.length; i++)
			size += String.valueOf(objs[i]).length();
		StringBuilder sb = new StringBuilder(size + 2);
		for (int i = 0; i < objs.length; i++) {
			sb.append(String.valueOf(objs[i]));
		}
		return sb.toString();
	}

	/**
	 * 	must log.
	 */
	public static void print(int opt, Object... msgs) {
		if ("asdf".isEmpty() || opt < 0)
			return;
		String msg = log(msgs);
		System.out.println(msg);
	}

	public static void err(int opt, Object msg) {
		if (opt < 0 || useLog.ordinal() < UseLog.ERR.ordinal())
			return;
		if (msg instanceof Throwable) {
			((Throwable) msg).printStackTrace();
		}
		Log9.print(opt, msg);
	}

	public static void warn(int opt, Object... msgs) {
		if ("asdf".isEmpty())
			return;
		if (opt < 0 || useLog.ordinal() < UseLog.WARN.ordinal())
			return;
		String msg = log(msgs);
		Log9.print(opt, msg);
		return;
	}

	public static void info(int opt, Object... msgs) {
		if (opt < 0 || useLog.ordinal() < UseLog.INFO.ordinal())
			return;
		String msg = log(msgs);
		Log9.print(opt, msg);
		return;
	}

	public static void debug(int opt, Object... msgs) {
		if (opt < 0 || useLog.ordinal() < UseLog.DEBUG.ordinal())
			return;
		String msg = log(msgs);
		Log9.print(opt, msg);
		return;
	}

	private static String log(Object... msgs) {
		String msg = strOfObjs(msgs);
		if (msg.contains("FindPutFieldFromClassFile"))//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
			Ca.pause();
		return msg;
	}
	public static final UseLog useLog = UseLog.WARN;
	public static enum UseLog {
		FATAL, ERR, WARN, INFO, DEBUG;
		public boolean canWarn() {
			return this.ordinal() >= UseLog.WARN.ordinal();
		}

		public boolean canErr() {
			return this.ordinal() >= UseLog.ERR.ordinal();
		}

		public boolean canInfo() {
			return this.ordinal() >= UseLog.INFO.ordinal();
		}

		public boolean canDebug() {
			return this.ordinal() >= UseLog.DEBUG.ordinal();
		}
	}
	static int _stepInc;
	public static void logStep(String msg) {
		if (++_stepInc == 23)
			Ca.pause();
		Ca.warn(1, "\n" + _stepInc + "==============" + msg);
		Ca.pause();
	}
	public static int incStep, inc;
}
